﻿/// <reference path="jquery-1.7.1.js" />

//兼容IE的事件注册方法
var Handler = {};
if (document.addEventListener) {
    Handler.add = function (elem, etype, fn) {
        elem.addEventListener(etype, fn, false);
    };
    Handler.remove = function (elem, etype, fn) {
        elem.removeEventListener(etype, fn, false);
    }
} else if (document.attachEvent) {
    Handler.add = function (elem, etype, fn) {
        if (-1 != Handler.find(elem, etype, fn)) return;

        var wrapHandler = function (e) {
            if (!e) e = window.event;
            var event = {
                _event: e,
                type: e.type,//返回发生的事件类型（名称）。不戴on前缀的,onclick事件，返回的type值为click
                target: e.srcElement,//返回发生事件的DOM对象
                currentTarget: elem,//可能和target值一样，也可能不一样。在事件处理函数中，应该使用这个属性，而不是this关键字
                relatedTarget: e.fromElement ? e.fromElement : e.toElement,//mouseover和mouseout两个事件中才会出现的事件属性
                eventPhase: (e.srcElement == elem) ? 2 : 3,//表示事件传播的过程段。

                clientX: e.clientX, clientY: e.clientY,
                screenX: e.screenX, screenY: e.screenY,

                altKey: e.altKey, ctrlKey: e.ctrlKey,
                shiftKey: e.shiftKey, charCode: e.keyCode,

                stopPropagation: function () { this._event.cancelBubble = true; },
                preventDefault: function () { this._event.returnValue = false; }
            }

            if (Function.prototype.call) {
                fn.call(elem, event);
            } else {
                elem._currentHandler = handler;
                elem._currentHandler(event);
                elem._currentHandler = null;
            }
        }
        elem.attachEvent("on" + etype, wrapHandler);

        var Event_obj = {
            elem: elem,
            etype: etype,
            fn: fn,
            wrapHandler: wrapHandler
        }
        var d = elem.document || document;
        var w = d.parentWindow;

        var Event_id = Handler.guid();
        if (!w.obj) w.obj = {};
        w.obj[Event_id] = Event_obj;
        if (!elem.arr) elem.arr = [];
        elem.arr.push(Event_id);

        if (!w.regiest) {
            w.regiest = true;
            w.attachEvent("onunload", Handler.removeallHandles);
        }
    };
    Handler.remove = function (elem, etype, fn) {
        var i = Handle.find(elem, etype, fn);
        if (-1 == i) return;

        var d = elem.document || document;
        var w = d.parentWindow;

        var evtId = elem.arr[i];
        var Event_obj = w.obj[evtId];
        elem.detachEvent("on" + etype, Event_obj.wrapHandler);
        elem.arr.splice(i, 1);
        delete w.obj[evtId];
    }
    Handler.find = function (elem, etype, fn) {
        var evts = elem.arr;
        if (!evts) return -1;

        var d = elem.document || document;
        var w = d.parentWindow;

        for (var k = 0, len = evts.length; k < len; k++) {
            var eventId = evts[k];
            var EvtObj = w[eventId];
            if (EvtObj.etype == etype && EvtObj.fn == fn) return k;
        }
        return -1;
    };
    Handler.removeallHandles = function () {
        var w = this;
        for (var id in w.obj) {
            var Event_obj = w.obj[id];
            Event_obj.elem.detachEvent("on" + Event_obj.etype, Event_obj.wrapHandler);
            delete w.obj[id];
        }
    };
    Handler.count = 0;
    Handler.guid = function () {
        return Handler.count++;
    }
}

//创建一个类，这个类方法用来创建一个新的类，使用Init方法初始化新类。方法可以接收一个参数，如果参数存在并且是个可继承的对象，那么新创建的类就会继承父类上的方法。
var mClass = function (parent) {
    var mlass = function () {
        this.init.apply(this, arguments);
    }

    if (parent) {
        var subClass = function () { };
        subClass.prototype = parent.prototype;
        mlass.prototype = new subClass;
    }

    mlass.prototype.init = function () { };
    mlass.fn = mlass.prototype;
    mlass.fn.parent = mlass;

    // mlass.super = __proto__;

    mlass.extend = function (obj) {
        var extended = obj.extended;
        for (var m in obj) {
            mlass[m] = obj[m];
        }
        if (extended) extended(mlass);
    }

    mlass.fn.extend = mlass.extend;

    mlass.include = function (obj) {
        var included = obj.included;
        for (var c in obj) {
            mlass.fn[c] = obj[c];
        }
        if (included) included(mlass);
    }
    mlass.fn.include = mlass.include;

    mlass.proxy = function (fn) {
        var self = this;
        return function () {
            return fn.apply(self, arguments);
        }
    }
    mlass.fn.proxy = mlass.proxy;

    return mlass;
}


var Animate = new mClass;

Animate.prototype.init = function (opt) {
    var opt = typeof (opt) == "undefined" ? {} : opt;
    this.opts = this.extend({}, opt);
    this.elem = this.opts.elem;
    if (!this.elem) { throw new ("不存在DOM对象"); return; }
        var flag = this.isEmptyObj(this.opts.styles);
        if (!flag) { throw new ("不存在Style对象"); return; } else { this.styles = this.opts.styles; }
        this.currstyles = this.parseStyle();
    var start = +new Date();
    var duration = this.opts.duration || 1000;
    var delay = this.opts.delay || 40;
    var callback = this.opts.callback;

    var self = this;
    var id = setInterval(function () {
        var timePassed = +new Date() - start;
        var progress = (timePassed / duration) > 1 ? 1 : (timePassed / duration);
        var delta = self.opts.delta != undefined ? self.delta(progress) : self.delta.linder(progress);
        self.step(delta);
        if (progress == 1) {
            clearInterval(id);
            callback & callback.apply(self, arguments);
        }
    }, delay);

};
Animate.include({
    delta: {//运动方式
        linder: function (x) {
            return x;
        },
        easeOutExpo: function (t) {
            return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
        }
    },
    step: function (delta) {
        var prop = this.styles;
        var curstyles = this.currstyles;
        for (var m in prop) {
            if (m == "width" || m == "height" || m == "marginLeft" || m == "marginRight" || m == "marginTop" || m == "marginBottom" || m == "left" || m == "top" || m == "bottom" || m == "right") {
                this.elem.style[m] = (curstyles[m] + (prop[m] - curstyles[m]) * delta).toFixed(3) + 'px';
            } else if (m == "color" || m == "backgroundColor") {
                this.setColor(m, delta);
            } else if (m == "opacity") {
                this.setOpacity(m, delta);
            }
        }
    },
    getStyle: function () {
        var styleObj = {};
        var dom = this.elem;
        var styles = this.styles;
        if (dom.currentStyle) {
            for (var k in styles) {
                if (k == "opacity") {
                    styleObj[k] = this.getOpacity();
                } else if (k == "color" || k == "backgroundColor") {
                    styleObj[k] = this.getColor(k);
                } else {
                    styleObj[k] = dom.currentStyle[k];
                }
            }
        }
        else if (window.getComputedStyle) {
            for (var k in styles) {
                if (k == "opacity") {
                    styleObj[k] = this.getOpacity();
                } else if (k == "color" || k == "backgroundColor") {
                    styleObj[k] = this.getColor(k);
                } else {
                    styleObj[k] = window.getComputedStyle(dom, null)[k];
                }
            }
        }
        return styleObj;
    },
    parseStyle: function () {
        var styleObj = this.getStyle();
        var dom = this.elem;
        var parseObj = {};
        var rect = dom.getBoundingClientRect();
        for (var k in styleObj) {
            if (k == "width" && styleObj[k] == "auto" || k == "height" && styleObj[k] == "auto") {
                parseObj[k] = k === 'width' ? rect.right - rect.left : rect.bottom - rect.top;
            } else if (k == "color" || k == "backgroundColor") {
                parseObj[k] = styleObj[k];
            } else {
                parseObj[k] = parseFloat(styleObj[k]);
            }
        }
        return parseObj;
    },
    getColor: function (s) {
        var dom = this.elem;
        var styles = this.styles;
        var color = {}, colorval;
        if (dom.currentStyle) {
            var cacheVal = dom.currentStyle[s].substring(1);
            if (cacheVal.length > 3) {
                color[0] = cacheVal.substring(0, 2);
                color[1] = cacheVal.substring(2, 4);
                color[2] = cacheVal.substring(4, 6);
            } else {
                color[0] = cacheVal.substring(0, 1);
                color[1] = cacheVal.substring(1, 2);
                color[2] = cacheVal.substring(2, 3);
            }
        }
        else if (window.getComputedStyle) {
            colorval = window.getComputedStyle(dom, null)[s];
            if (/#/.test(colorval)) {
                var co = colorval.match(/\d+/g);
                for (var i = 0, l = co.length; i < l; i++) {
                    color[i] = parseInt(co[i], 16);
                }
            } else if (/rgb/.test(colorval)) {
                var co = colorval.match(/\d+/g);
                color[0] = co[0];
                color[1] = co[1];
                color[2] = co[2];
            }
        }
        return color;
    },
    setColor: function (sty, delta) {
        var curstyles = this.currstyles;
        var prop = this.styles;
        var red = curstyles[sty][0], green = curstyles[sty][1], blue = curstyles[sty][2];
        var patten = /#/, r, g, b;
        if (patten.test(prop[sty])) {
            var newc = prop[sty].substring(1);
            if (newc.length > 3) {
                r = red <= parseInt(newc.substring(0, 2), 16) ? (red + (parseInt(newc.substring(0, 2), 16) * delta).toFixed(0)) : red - ((red - parseInt(newc.substring(0, 2), 16)) * delta).toFixed(0);
                g = green <= parseInt(newc.substring(2, 4), 16) ? green + (parseInt(newc.substring(2, 4), 16) * delta).toFixed(0) : green - ((green - parseInt(newc.substring(2, 4), 16)) * delta).toFixed(0);
                b = blue <= parseInt(newc.substring(4, 6), 16) ? blue + (parseInt(newc.substring(4, 6), 16) * delta).toFixed(0) : blue - ((blue - parseInt(newc.substring(4, 6), 16)) * delta).toFixed(0);
            } else {
                var a = newc[0] + newc[0], c = newc[1] + newc[1], d = newc[1] + newc[1];
                r = red <= parseInt(a, 16) ? red + (parseInt(a, 16) * delta).toFixed(0) : red - ((red - parseInt(a, 16)) * delta).toFixed(0);
                g = green <= parseInt(c, 16) ? green + (parseInt(c, 16) * delta).toFixed(0) : green - ((green - parseInt(c, 16)) * delta).toFixed(0);
                b = blue <= parseInt(d, 16) ? blue + (parseInt(d, 16) * delta).toFixed(0) : blue - ((blue - parseInt(c, 16)) * delta).toFixed(0);
            }
        } else if (/rgb/.test(prop[sty])) {
            var rgbNum = (prop[sty].match(/\d+/g));
            r = red <= rgbNum[0] ? red + (rgbNum[0] * delta).toFixed(0) : red - ((red - rgbNum[0]) * delta).toFixed(0);
            g = green <= rgbNum[1] ? green + (rgbNum[1] * delta).toFixed(0) : green - ((green - rgbNum[1]) * delta).toFixed(0);
            b = blue <= rgbNum[2] ? blue + (rgbNum[2] * delta).toFixed(0) : blue - ((blue - rgbNum[2]) * delta).toFixed(0);
        };
        this.elem.style[sty] = "rgb(" + r + "," + g + "," + b + ")";
    },
    getOpacity: function () {
        var opac;
        var dom = this.elem;
        if (window.getComputedStyle) {//火狐
            opac = window.getComputedStyle(dom, null)["opacity"];
        } else if (dom.currentStyle) {//IE
            var filter = dom.currentStyle["filter"];
            var patten = /opacity/;
            if (patten.test(filter)) {
                var val = filter.match(/\d+/) / 100;
                opac = (val == 1 || val == 0) ? val.toFixed(0) : val.toFixed(1);
            } else {
                opac = 1;
            }
        }
        return opac;
    },
    setOpacity: function (sty, delta) {
        var curstyles = this.currstyles;
        var prop = this.styles;
        var dom = this.elem;
        if (dom.currentStyle) {
            opa = curstyles[sty] <= prop[sty] ? curstyles[sty] + (prop[sty] * delta).toFixed(2) : curstyles[sty] - ((curstyles[sty] - prop[sty]) * delta).toFixed(2);
            dom.style.filter = opa === 1 ? '' : 'alpha(opacity=' + opa * 100 + ')';
            dom.style[sty] = opa;
        }
        else if (window.getComputedStyle) {
            opa = curstyles[sty] <= prop[sty] ? curstyles[sty] + (prop[sty] * delta).toFixed(2) : curstyles[sty] - ((curstyles[sty] - prop[sty]) * delta).toFixed(2);
            dom.style[sty] = opa;
        }
    },
    isEmptyObj: function (obj) {
        var flag = false;
        if (obj == undefined) return flag;
        for (var i in obj) {
            if (obj[i] != undefined) { flag = true; return flag; }
        }
        return flag;
    },
    extend: function (des, src) {
        for (var k in src) {
            des[k] = src[k];
        }
        return des;
    }
});